/*
 * @Author: xiaosihan 
 * @Date: 2024-08-17 22:10:13 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-08-20 20:08:03
 */

import { round } from "lodash";
import { BufferAttribute, Camera, DoubleSide, Intersection, Mesh, MeshLambertMaterial, MeshStandardMaterial, PlaneGeometry, Raycaster, RepeatWrapping, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from "three";
import { degToRad } from "three/src/math/MathUtils";
import caodiPNG from "./caodi.png";
import CtxMesh from "./CtxMesh";
import { Octree } from "three/examples/jsm/math/Octree";
import { OctreeHelper } from 'three/examples/jsm/helpers/OctreeHelper.js';

// 地形对象
export default class Terrain extends Mesh {

    constructor() {
        super();
    }

    // 八叉树
    octree = (() => {
        const octree = new Octree();
        octree.split(3);
        return octree;
    })();

    geometry = (() => {
        const geometry = new PlaneGeometry(100, 100, 200, 200);
        geometry.rotateX(degToRad(-90));
        return geometry;
    })();

    originPosition = new BufferAttribute(new Float32Array([]), 3);

    textureLoader = new TextureLoader();

    map = (() => {
        const map = this.textureLoader.load(caodiPNG);
        map.wrapS = RepeatWrapping
        map.wrapT = RepeatWrapping
        map.offset.set(0.5, 0.5) // 设置偏移量
        map.anisotropy = 4
        map.repeat.set(100 / 20, 100 / 20)
        map.colorSpace = SRGBColorSpace
        return map;
    })();

    // 创建阴影
    castShadow = true;
    // 接受阴影
    receiveShadow = true;

    material = new MeshStandardMaterial({
        map: this.map,
        side: DoubleSide
    });

    // 编辑画笔的参数
    ctxParam: {
        ctxSize: number,
        ctxIntensity: number
    } = {
            ctxSize: 10,
            ctxIntensity: 1
        }

    // 贝塞尔曲线
    bezier: [number, number, number, number] = [0.7, 0, 0.3, 1];
    // x轴贝塞尔
    Xbezier: [number, number, number, number] = [0, 0.7, 0.3, 1];
    // y轴贝塞尔
    Ybezier: [number, number, number, number] = [0, 0, 1, 1];
    componentBezier(arr: [number, number, number, number], t: number) {
        const ut = 1 - t;
        const a1 = arr[1] * ut + arr[2] * t;
        const result = ((arr[0] * ut + arr[1] * t) * ut + a1 * t) * ut + (a1 * ut + (arr[2] * ut + arr[3] * t) * t) * t;
        return result;
    }

    //画笔模型
    ctxMesh = (() => {
        const ctxMesh = new CtxMesh();
        ctxMesh.visible = false;
        const { ctxSize } = this.ctxParam;
        ctxMesh.scale.set(ctxSize, ctxSize, ctxSize);
        this.add(ctxMesh);
        return ctxMesh;
    })();

    // 射线
    raycaster = new Raycaster();

    // 通过坐标获取地形的高度
    getYByXZ(x: number, z: number) {
        this.raycaster.ray.direction.set(0, -1, 0);
        this.raycaster.ray.origin.set(x, 1000, z);
        this.raycaster.far = Infinity;

        const r = this.octree.rayIntersect(this.raycaster.ray);
        if (r) {
            return r.position.y;
        } else {
            return 0;
        }

        // const intersect = this.raycaster.intersectObject(this, false)[0];
        // if (intersect && intersect.point) {
        //     return intersect.point.y;
        // } else {
        //     return 0;
        // }
    }

    //设置画笔
    setEditor(ctxParam: Partial<{ ctxSize: number, ctxIntensity: number }>) {
        const { ctxSize } = Object.assign(this.ctxParam, ctxParam);
        this.ctxMesh.scale.set(ctxSize, ctxSize, ctxSize);
    }

    // 判断鼠标是否拾取到这个地形
    intersect(mosePosition: Vector2, camera: Camera) {
        this.raycaster.setFromCamera(mosePosition, camera);
        return this.raycaster.intersectObject(this, false)[0];
    }

    //鼠标事件
    mousedown(intersection: Intersection) {
        const position = this.geometry.getAttribute("position") as BufferAttribute;
        this.originPosition.copy(position);
        this.ctxMesh.visible = true;
        this.ctxMesh.position.copy(intersection.point).add(intersection.normal!)
        this.ctxMesh.lookAt(intersection.point.add(intersection.normal!.multiplyScalar(2)));
        this.drawGeometry(intersection);
    }
    mouseup() {
        this.ctxMesh.visible = false;
    }
    mousemove(intersection: Intersection) {
        if (!this.ctxMesh.visible) {
            return;
        }
        this.drawGeometry(intersection);
    }
    drawGeometry(intersection: Intersection) {
        const { ctxSize, ctxIntensity } = this.ctxParam;
        this.ctxMesh.position.copy(intersection.point).add(intersection.normal!)
        this.ctxMesh.lookAt(intersection.point.add(intersection.normal!.multiplyScalar(2)));
        //绘制地形
        const position = this.geometry.getAttribute("position") as BufferAttribute;
        const tempV3 = new Vector3();
        for (let i = 0; i < position.count; i++) {
            tempV3.set(this.originPosition.getX(i), intersection.point.y, this.originPosition.getZ(i));
            const distance = tempV3.distanceTo(intersection.point);
            if (distance <= ctxSize) {
                const d = (distance / ctxSize);
                // 斜率
                let t = 0;
                // 微分法 求斜率t
                while (this.componentBezier(this.Xbezier, t + 0.1) < d) {
                    t += 0.1;
                }
                while (this.componentBezier(this.Xbezier, t + 0.01) < d) {
                    t += 0.01;
                }
                while (this.componentBezier(this.Xbezier, t + 0.001) < d) {
                    t += 0.001;
                }
                t = Math.min(1, Math.max(0, t))  // 斜率最大为1
                // 通过斜率求y值
                const y = this.componentBezier(this.Ybezier, t);
                const offset = (1 - y) * ctxIntensity;
                position.setY(i, Math.max(position.getY(i), this.originPosition.getY(i) + offset));
            }
            position.needsUpdate = true;
        }
    }
    // 初始化网格
    normalGeometry() {
        const position = this.geometry.getAttribute("position") as BufferAttribute;
        for (let i = 0; i < position.count; i++) {
            position.setY(i, 0);
        }
        position.needsUpdate = true;
        this.originPosition.copy(position);
    }

    // 导出数据
    exportData() {
        const position = this.geometry.getAttribute("position");
        const data = [...position.array].map(v => round(v, 3));
        return data;
    }
    // 下载数据
    downloadData() {
        const data = this.exportData();
        const text = JSON.stringify(data);
        const blob = new Blob([text], { type: 'text/plain' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = "terrain.json";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }
    //导入数据
    importData(data: Array<number> = [0, 0, 0]) {
        let positionArray = new Float32Array(data);
        let position = new BufferAttribute(positionArray, 3, false);
        this.geometry.setAttribute("position", position);
        this.originPosition.copy(position);
        this.octree.clear();
        this.octree.fromGraphNode(this);
    }


}